package com.open.demo.mvvm.demo

import android.util.Log
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.open.demo.mvvm.Constants
import com.open.demo.mvvm.bean.Result
import com.open.demo.mvvm.engine.BaseViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

/**
 *
 * @Author: hailong.qiu hailong.qiu@xgimi.com
 * @Maintainer: hailong.qiu hailong.qiu@xgimi.com
 * @Date: 2022/2/17
 * @Copyright: 2022 www.xgimi.com Inc. All rights reserved.
 */
class SearchViewModel() : BaseViewModel() {

    private val searchRepository by lazy { SearchRepository() }

    var history = searchRepository.getHistory()
        .onStart {
            // 显示加载
            Result.Loading<String>("加载中...")
            Log.d(Constants.TAG, "onStart---${Thread.currentThread().name}")
        }
    // 如果你不想多次收集相同的值呢？那么你就可以使用distinctUntilChanged操作符，它只在值与前一个值不同时发送。
    //        .distinctUntilChanged()
        .filter { // 过滤运算符:过滤数值
//            delay(2000)
            Log.d(Constants.TAG, "filter---${Thread.currentThread().name}")
            true
        }
        // 由于Flow是顺序的，collecting一个值的总执行时间是所有运算符的执行时间之和。
        // 如果你有一个长期运行的运算符，你可以使用buffer，这样直到buffer的所有运算符的执行将在一个不同的coroutine中处理，而不是在协程中对Flow collect。
        // 这使得总的执行速度更快。
        //        .buffer()
        // map 修改数值
        .map {
            delay(500)
            Log.d(Constants.TAG, "map---${Thread.currentThread().name}")
            if (it is Result.Success) {
                // 将相关数据转换下
                it
            } else {
                it
            }
        }
        // transform操作符对数据进行转换，这使你可以灵活地对一个单一的值发出你想要的信息。
        //        .transform<String> {
        //            emit("fuck sb!")
        //        }
        // 比方说，你只想在显示在用户界面之前缓存修改过的数据。你可以利用onEach操作符来完成每个值的工作。
        .onEach {
            println("onEach $it")
        }
        // 如果你在所有运算符中做一些繁重的工作，你可以通过使用flowOn运算符简单地改变整个运算符的执行环境。
        .flowOn(Dispatchers.Default)
        // 错误怎么处理？只需使用catch操作符来捕捉下行流中的任何错误。
        .catch {
        }
        // 完成
        .onCompletion {
        }

    // 如果我们有另一个流 要与 history流合并呢？
    // (你可能会认为这是一个有多个LiveData源的MediatorLiveData）你可以使用合并函数来合并任何数量的流量。
    val serachForecast: Flow<Result<List<SearchData>>> get() = merge(history, history)

    val searchListLiveData = MutableLiveData<Result<List<SearchData>>>()
    private val searchListStateFlow = MutableStateFlow<Result<*>>(Result.Loading("加载UI中"))
    val searchListState:StateFlow<Result<*>> = searchListStateFlow

    fun getSearchList(key: String) {
//        lifecycleScope.launchWhenStarted {  }
//        lifecycleScope.launchWhenResumed {  }
//        lifecycleScope.launchWhenCreated {  }
        launchUI {
            searchRepository.getSearchList(key)
                .collect {
                    searchListStateFlow.value = it
                }
        }
    }

}